package com.xinhuo.demo.aspect;

import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;

/**
 * @Auther: zhangxinlin
 * @Date: 2019/5/17 10:10:40
 * @Description:
 */
@Aspect
@Component
public class ControllerAspect {

    private Logger logger = LoggerFactory.getLogger(getClass());

    /*@PointCut注解表示表示横切点，哪些方法需要被横切*/
    @Pointcut("execution(* com.xinhuo.demo.web.StudentController.*(..))")
    public void pointCut() {

    }

    /**
     * 前置通知：方法调用前被调用
     * 通过JoinPoint 获取通知的签名信息，如目标方法名，目标方法参数信息等
     * 在进入每个controller的接口的开始时先进入这个方法
     * 把接口中的requestMsg参数重新设置进request
     * @param joinPoint
     */
//    @Before("execution(* com.xinhuo.demo.web..*.*(..))")
    @Before("execution(* com.xinhuo.demo.web.StudentController.*(..))")
    public void beforeController(JoinPoint joinPoint){
        logger.info("aop before");
        //获取接口的参数，设置回request
        Object[] o = joinPoint.getArgs();
//        RequestMsg requestMsg = (RequestMsg) o[0];
        //获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        //从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        request.setAttribute("body",o[0]);
    }

    /**
     * 后置返回通知
     * @AfterReturning注解用于获取方法的返回值
     * @param object
     */
    @AfterReturning(pointcut = "pointCut()", returning = "object")
    public void getAfterReturn(Object object) {
        logger.info("aop afterReturning");
        logger.info("aop afterReturning返回值:{}", JSONObject.toJSONString(object));
    }

    /**
     * 后置最终通知（目标方法只要执行完了就会执行后置通知方法）
     * @After注解表示在方法执行之后执行
     */
    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        logger.info("aop after");
    }

    /**
     * 后置异常通知
     * 当目标方法抛出异常返回后，将把目标方法抛出的异常传给通知方法；
     */
    @AfterThrowing(value="pointCut()",throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint,Throwable exception) {
        logger.info("aop afterThrowing");
    }
}
